package com.whl215.customview.flipboard

import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import androidx.core.animation.doOnEnd
import com.whl215.customview.R


/**
 * Flipboard 3D变换效果
 */
class TransformView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    private val mCamera: Camera = Camera()
    private val mBitmap: Bitmap by lazy {
        BitmapFactory.decodeResource(resources, R.drawable.ic_head_portrait)
    }
    private val mPaint: Paint by lazy {
        val paint = Paint()
        paint.isAntiAlias = true
        return@lazy paint
    }

    private var degreeRotate = 0f
        set(value) {
            field = value
            invalidate()
        }
    private var degreeRightY = 0f
        set(value) {
            field = value
            invalidate()
        }

    private var degreeLeftY = 0f
        set(value) {
            field = value
            invalidate()
        }
    private var animRotate = ObjectAnimator.ofFloat(this, "degreeRotate", 0f, 360f)
    private var animDegreeRightY = ObjectAnimator.ofFloat(this, "degreeRightY", 0f, -45f)
    private var animDegreeRightReset = ObjectAnimator.ofFloat(this, "degreeRightY",-45f, 0f )
    private var animDegreeLeftY = ObjectAnimator.ofFloat(this, "degreeLeftY", 0f, 45f)
    private var animDegreeLeftReset = ObjectAnimator.ofFloat(this, "degreeLeftY", 45f, 0f)


    init {
        val displayMetrics = resources.displayMetrics
        val newZ = -displayMetrics.density * 6
        mCamera.setLocation(0f, 0f, newZ)
        animRotate.duration = 2000
        animDegreeRightY.duration = 2000
        animDegreeLeftY.duration = 2000
        animDegreeRightReset.duration = 2000
        animDegreeLeftReset.duration = 2000
        animDegreeRightY.doOnEnd {
            animRotate.start()
        }
        animRotate.doOnEnd {
            animDegreeLeftY.start()
        }
        animDegreeLeftY.doOnEnd {
            animDegreeRightReset.startDelay=1000
            animDegreeLeftReset.startDelay=1000
            animDegreeRightReset.start()
            animDegreeLeftReset.start()
        }
        animDegreeLeftReset.doOnEnd {
            animDegreeRightY.start()
        }
//        setOnClickListener {
//            animDegreeRightY.start()
//        }
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        animDegreeRightY.start()
    }

    override fun onDetachedFromWindow() {
        animRotate.cancel()
        animDegreeLeftReset.cancel()
        animDegreeLeftY.cancel()
        animDegreeRightReset.cancel()
        animDegreeRightY.cancel()
        super.onDetachedFromWindow()
    }


    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
//        drawFrame1(canvas)
//        drawFrame2(canvas)
//        drawFrame3(canvas)
//        drawFrame4(canvas)
//        drawFrame5(canvas)
//        drawFrame6(canvas)
//        drawFrame7(canvas)
        drawFrame8(canvas)
    }

    /**
     * 居中 画一张图片
     */
    private fun drawFrame1(canvas: Canvas) {
        val bWidth = mBitmap.width
        val bHeight = mBitmap.height
        val centerX = width / 2
        val centerY = height / 2
        val x = centerX - bWidth / 2f
        val y = centerY - bHeight / 2f
        canvas.drawBitmap(mBitmap, x, y, mPaint)
    }


    /**
     * 裁切一半图片
     */
    private fun drawFrame2(canvas: Canvas) {
        val bWidth = mBitmap.width
        val bHeight = mBitmap.height
        val centerX = width / 2
        val centerY = height / 2
        val x = centerX - bWidth / 2f
        val y = centerY - bHeight / 2f
        canvas.save()
        canvas.clipRect(centerX.toFloat(), y, x + bWidth, y + bHeight)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()
    }


    /**
     * 使用camera，旋转整张图片
     */
    private fun drawFrame3(canvas: Canvas) {
        val bWidth = mBitmap.width
        val bHeight = mBitmap.height
        val centerX = width / 2
        val centerY = height / 2
        val x = centerX - bWidth / 2f
        val y = centerY - bHeight / 2f

        canvas.save()
        canvas.translate(centerX.toFloat(), centerY.toFloat())
        mCamera.save()
        mCamera.rotateY(-30f)
        mCamera.applyToCanvas(canvas)
        mCamera.restore()
        canvas.translate(-centerX.toFloat(), -centerY.toFloat())
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()
    }


    /**
     * 使用camera+裁切 使一半图片 3D旋转
     */
    private fun drawFrame4(canvas: Canvas) {
        val bWidth = mBitmap.width
        val bHeight = mBitmap.height
        val centerX = width / 2
        val centerY = height / 2
        val x = centerX - bWidth / 2f
        val y = centerY - bHeight / 2f
        canvas.save()
        canvas.translate(centerX.toFloat(), centerY.toFloat())
        mCamera.save()
        mCamera.rotateY(-30f)
        mCamera.applyToCanvas(canvas)
        mCamera.restore()
        canvas.translate(-centerX.toFloat(), -centerY.toFloat())
        canvas.clipRect(centerX.toFloat(), y, x + bWidth, y + bHeight)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()
    }


    /**
     * 纸张对折效果，对折线居中
     * 一半不动 静态平面，一半3D旋转，
     */
    private fun drawFrame5(canvas: Canvas) {
        val bWidth = mBitmap.width
        val bHeight = mBitmap.height
        val centerX = width / 2
        val centerY = height / 2
        val x = centerX - bWidth / 2f
        val y = centerY - bHeight / 2f

        //静态
        canvas.save()
        canvas.clipRect(x, y, x + bWidth / 2, y + bHeight)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()

        //3D旋转
        canvas.save()
        canvas.translate(centerX.toFloat(), centerY.toFloat())
        mCamera.save()
        mCamera.rotateY(-45f)
        mCamera.applyToCanvas(canvas)
        mCamera.restore()
        canvas.translate(-centerX.toFloat(), -centerY.toFloat())
        canvas.clipRect(centerX.toFloat(), y, x + bWidth, y + bHeight)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()
    }


    /**
    体会坐标系
    代码中注释1 ，注释2 作用完全一样 裁切canvas 但是位置不同，
    注释1在 canvas.translate上方先执行 注释2在canvas.translate 下方后执行，运行效果完全不同
    因为坐标系改变了，canvas.translate 改变canvas的绘制原点
    默认原点 (0,0) view左上角 第一次调用 canvas.translate 原点移动到 计算的位置centerX，centerY
    注释1的裁切 是以(centerX,centerY) 为原点。
    第二次 调用canvas.translate 把原点移动回(0,0)，注释2的裁切以(0,0)为原点
    原点不同 用同样坐标肯定效果不一致

    ...
    canvas.translate(centerX.toFloat(),centerY.toFloat())
    canvas.clipRect(centerX.toFloat(), y,x+bWidth, y + bHeight)
    canvas.translate(-centerX.toFloat(),-centerY.toFloat())
    canvas.clipRect(centerX.toFloat(), y,x+bWidth, y + bHeight)
    ...

    注释1的裁切 想要正常显示 需要(centerX,centerY)为原点重新计算坐标 进行裁切。
     */
    private fun drawFrame6(canvas: Canvas) {
        val bWidth = mBitmap.width
        val bHeight = mBitmap.height
        val centerX = width / 2
        val centerY = height / 2
        val x = centerX - bWidth / 2f
        val y = centerY - bHeight / 2f

        //静态
        canvas.save()
        //按照原点(0,0)裁剪
        canvas.clipRect(x, y, x + bWidth / 2, y + bHeight)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()

        //3D旋转
        canvas.save()
        canvas.translate(centerX.toFloat(), centerY.toFloat())
        mCamera.save()
        mCamera.rotateY(-45f)
        mCamera.applyToCanvas(canvas)
        mCamera.restore()
        //1 (centerX,centerY)是原点 == (0,0)
        canvas.clipRect(
            0f, -bHeight / 2f,
            bWidth / 2f, bHeight / 2f
        )
//        canvas.clipRect(centerX.toFloat(), y,x+bWidth, y + bHeight)
        canvas.translate(-centerX.toFloat(), -centerY.toFloat())
        //2 (0,0)是原点
//        canvas.clipRect(centerX.toFloat(), y,x+bWidth, y + bHeight)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()
    }


    /**
    纸张对折效果，改变对折线角度 不居中 斜着对折
    做UI吧 你看起来是效果A 第一思路是直接实现效果A，但是发现直接实现不了，绞尽脑汁也没办法。
    怎么办呢 后来灵机一动 效果B+效果C == 效果A。 看起来和真的一样，其他不知道你怎么实现的人 觉得你好牛逼 直接实现了效果A
    实际上取巧了 假的A， 真的B+C
    原生 并没有提供 斜着切的api 比如 一块正方形的纸 45°对折。有两种办法
    1.直接上手 两角对齐  达成 45°对折
    2.先旋转45° 在90°对折  然后旋转45° 回到初始位置
    两种办法的视觉效果是一致的
     */
    private fun drawFrame7(canvas: Canvas) {
        val bWidth = mBitmap.width.toFloat()
        val bHeight = mBitmap.height.toFloat()
        val centerX = width / 2f
        val centerY = height / 2f
        val x = centerX - bWidth / 2f
        val y = centerY - bHeight / 2f

        //静态
        canvas.save()
        canvas.translate(centerX, centerY)
        canvas.rotate(-degreeRotate)
        //因为有旋转图片的需要 裁切位置太小 会使图片位置显示不全 所以放大一点
        canvas.clipRect(-bWidth, -bHeight, 0f, bHeight)
        canvas.rotate(30f)
        canvas.translate(-centerX, -centerY)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()

        //3D旋转
        canvas.save()
        canvas.translate(centerX, centerY)
        canvas.rotate(-30f)//旋转canvas
        mCamera.save()//旋转状态下，Camera3D变换
        mCamera.rotateY(-45f)
        mCamera.applyToCanvas(canvas)
        mCamera.restore()
        canvas.clipRect(
            0f, -bHeight,
            bWidth, bHeight
        )//旋转状态下，裁剪canvas
        canvas.rotate(30f)//旋转回初始位置
        canvas.translate(-centerX, -centerY)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()
    }


    /**
     * 执行动画
     * 1.左边 45°抬起
     * 2.旋转 270°
     * 3.另一边 45°抬起
     * 4.维持两秒后 同时落下
     */
    private fun drawFrame8(canvas: Canvas) {
        val bWidth = mBitmap.width.toFloat()
        val bHeight = mBitmap.height.toFloat()
        val centerX = width / 2f
        val centerY = height / 2f
        val x = centerX - bWidth / 2f
        val y = centerY - bHeight / 2f

        //静态
        canvas.save()
        canvas.translate(centerX, centerY)
        canvas.rotate(-degreeRotate)
        mCamera.save()
        mCamera.rotateY(degreeLeftY)
        mCamera.applyToCanvas(canvas)
        mCamera.restore()
        //因为有旋转图片的需要 裁切位置太小 会使图片位置显示不全 所以放大一点
        canvas.clipRect(-bWidth, -bHeight, 0f, bHeight)
        canvas.rotate(degreeRotate)
        canvas.translate(-centerX, -centerY)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()

        //3D旋转
        canvas.save()
        canvas.translate(centerX, centerY)
        canvas.rotate(-degreeRotate)
        mCamera.save()
        mCamera.rotateY(degreeRightY)
        mCamera.applyToCanvas(canvas)
        mCamera.restore()
        canvas.clipRect(
            0f, -bHeight,
            bWidth, bHeight
        )
        canvas.rotate(degreeRotate)
        canvas.translate(-centerX, -centerY)
        canvas.drawBitmap(mBitmap, x, y, mPaint)
        canvas.restore()
    }
}